home *** CD-ROM | disk | FTP | other *** search
/ GameStar 2004 April / Gamestar_61_2004-04_dvdb.iso / DVDStar / Editace / hltp.exe / {app} / Source Code / Zoners Half-Life Tools / hlcsg / qcsg.cpp < prev    next >
C/C++ Source or Header  |  2002-12-08  |  53KB  |  1,721 lines

  1. /*
  2.  
  3.     CONSTRUCTIVE SOLID GEOMETRY    -aka-    C S G 
  4.  
  5.     Code based on original code from Valve Software, 
  6.     Modified by Sean "Zoner" Cavanaugh (seanc@gearboxsoftware.com) with permission.
  7.     Modified by Tony "Merl" Moore (merlinis@bigpond.net.au) [AJM]
  8.     
  9. */
  10.  
  11. #include "csg.h" 
  12.  
  13. /*
  14.  
  15.  NOTES
  16.  
  17.  - check map size for +/- 4k limit at load time
  18.  - allow for multiple wad.cfg configurations per compile
  19.  
  20. */
  21.  
  22. static FILE*    out[NUM_HULLS]; // pointer to each of the hull out files (.p0, .p1, ect.)  
  23. static int      c_tiny;        
  24. static int      c_tiny_clip;
  25. static int      c_outfaces;
  26. static int      c_csgfaces;
  27. BoundingBox     world_bounds;
  28.  
  29. #ifdef HLCSG_WADCFG
  30. char            wadconfigname[MAX_WAD_CFG_NAME];
  31. #endif
  32.  
  33. vec_t           g_tiny_threshold = DEFAULT_TINY_THRESHOLD;
  34.      
  35. bool            g_noclip = DEFAULT_NOCLIP;              // no clipping hull "-noclip"
  36. bool            g_onlyents = DEFAULT_ONLYENTS;          // onlyents mode "-onlyents"
  37. bool            g_wadtextures = DEFAULT_WADTEXTURES;    // "-nowadtextures"
  38. bool            g_chart = DEFAULT_CHART;                // show chart "-chart"
  39. bool            g_skyclip = DEFAULT_SKYCLIP;            // no sky clipping "-noskyclip"
  40. bool            g_estimate = DEFAULT_ESTIMATE;          // progress estimates "-estimate"
  41. bool            g_info = DEFAULT_INFO;                  // "-info" ?
  42. const char*     g_hullfile = NULL;                      // external hullfile "-hullfie sdfsd"
  43.  
  44. #ifdef ZHLT_NULLTEX // AJM
  45. bool            g_bUseNullTex = DEFAULT_NULLTEX;        // "-nonulltex"
  46. #endif
  47.  
  48. #ifdef HLCSG_CLIPECONOMY // AJM
  49. bool            g_bClipNazi = DEFAULT_CLIPNAZI;         // "-noclipeconomy"
  50. #endif
  51.  
  52. #ifdef HLCSG_AUTOWAD // AJM
  53. bool            g_bWadAutoDetect = DEFAULT_WADAUTODETECT; // "-wadautodetect"
  54. #endif
  55.  
  56. #ifdef ZHLT_DETAIL // AJM
  57. bool            g_bDetailBrushes = DEFAULT_DETAIL; // "-detail"
  58. #endif
  59.  
  60. #ifdef ZHLT_PROGRESSFILE // AJM
  61. char*           g_progressfile = DEFAULT_PROGRESSFILE; // "-progressfile path"
  62. #endif
  63.  
  64. #ifdef ZHLT_INFO_COMPILE_PARAMETERS
  65. // =====================================================================================
  66. //  GetParamsFromEnt
  67. //      parses entity keyvalues for setting information
  68. // =====================================================================================
  69. void            GetParamsFromEnt(entity_t* mapent)
  70. {
  71.     int     iTmp;
  72.     char    szTmp[256];
  73.  
  74.     Log("\nCompile Settings detected from info_compile_parameters entity\n");
  75.  
  76.     // verbose(choices) : "Verbose compile messages" : 0 = [ 0 : "Off" 1 : "On" ]
  77.     iTmp = IntForKey(mapent, "verbose");
  78.     if (iTmp == 1)
  79.     {
  80.         g_verbose = true;
  81.     }
  82.     else if (iTmp == 0)
  83.     {
  84.         g_verbose = false;
  85.     }
  86.     Log("%30s [ %-9s ]\n", "Compile Option", "setting");
  87.     Log("%30s [ %-9s ]\n", "Verbose Compile Messages", g_verbose ? "on" : "off");
  88.  
  89.     // estimate(choices) :"Estimate Compile Times?" : 0 = [ 0: "Yes" 1: "No" ]
  90.     if (IntForKey(mapent, "estimate")) 
  91.     {
  92.         g_estimate = true;
  93.     }
  94.     else
  95.     {
  96.         g_estimate = false;
  97.     }
  98.     Log("%30s [ %-9s ]\n", "Estimate Compile Times", g_estimate ? "on" : "off");
  99.  
  100.     // priority(choices) : "Priority Level" : 0 = [    0 : "Normal" 1 : "High"    -1 : "Low" ]
  101.     if (!strcmp(ValueForKey(mapent, "priority"), "1"))
  102.     {
  103.         g_threadpriority = eThreadPriorityHigh;
  104.         Log("%30s [ %-9s ]\n", "Thread Priority", "high");
  105.     }
  106.     else if (!strcmp(ValueForKey(mapent, "priority"), "-1"))
  107.     {
  108.         g_threadpriority = eThreadPriorityLow;
  109.         Log("%30s [ %-9s ]\n", "Thread Priority", "low");
  110.     }
  111.  
  112.     // texdata(string) : "Texture Data Memory" : "4096"
  113.     iTmp = IntForKey(mapent, "texdata") * 1024;
  114.     if (iTmp > g_max_map_miptex)
  115.     {
  116.         g_max_map_miptex = iTmp;
  117.     }
  118.     sprintf(szTmp, "%i", g_max_map_miptex);
  119.     Log("%30s [ %-9s ]\n", "Texture Data Memory", szTmp);
  120.  
  121.     // hullfile(string) : "Custom Hullfile"
  122.     if (ValueForKey(mapent, "hullfile"))
  123.     {
  124.         g_hullfile = ValueForKey(mapent, "hullfile");
  125.         Log("%30s [ %-9s ]\n", "Custom Hullfile", g_hullfile);
  126.     }
  127.  
  128. #ifdef HLCSG_AUTOWAD
  129.     // wadautodetect(choices) : "Wad Auto Detect" : 0 =    [ 0 : "Off" 1 : "On" ]
  130.     if (!strcmp(ValueForKey(mapent, "wadautodetect"), "1"))
  131.     { 
  132.         g_bWadAutoDetect = true;
  133.     }
  134.     else
  135.     {
  136.         g_bWadAutoDetect = false;
  137.     }
  138.     Log("%30s [ %-9s ]\n", "Wad Auto Detect", g_bWadAutoDetect ? "on" : "off");
  139. #endif
  140.  
  141. #ifdef HLCSG_WADCFG
  142.     // wadconfig(string) : "Custom Wad Configuration" : ""
  143.     if (strlen(ValueForKey(mapent, "wadconfig")) > 0)
  144.     { 
  145.         safe_strncpy(wadconfigname, ValueForKey(mapent, "wadconfig"), MAX_WAD_CFG_NAME);
  146.         Log("%30s [ %-9s ]\n", "Custom Wad Configuration", wadconfigname);
  147.     }
  148. #endif
  149.  
  150. #ifdef HLCSG_CLIPECONOMY
  151.     // noclipeconomy(choices) : "Strip Uneeded Clipnodes?" : 1 = [ 1 : "Yes" 0 : "No" ]
  152.     iTmp = IntForKey(mapent, "noclipeconomy");
  153.     if (iTmp == 1)
  154.     {
  155.         g_bClipNazi = true;
  156.     }
  157.     else if (iTmp == 0)
  158.     {
  159.         g_bClipNazi = false;
  160.     }        
  161.     Log("%30s [ %-9s ]\n", "Clipnode Economy Mode", g_bClipNazi ? "on" : "off");
  162. #endif
  163.  
  164.     /*
  165.     hlcsg(choices) : "HLCSG" : 1 =
  166.     [
  167.         1 : "Normal"
  168.         2 : "Onlyents"
  169.         0 : "Off"
  170.     ]
  171.     */
  172.     iTmp = IntForKey(mapent, "hlcsg");
  173.     g_onlyents = false;
  174.     if (iTmp == 2)
  175.     {
  176.         g_onlyents = true;
  177.     }
  178.     else if (iTmp == 0)
  179.     {
  180.         Fatal(assume_TOOL_CANCEL, 
  181.             "%s was set to \"Off\" (0) in info_compile_parameters entity, execution cancelled", g_Program);
  182.         CheckFatal();  
  183.     }
  184.     Log("%30s [ %-9s ]\n", "Onlyents", g_onlyents ? "on" : "off");
  185.  
  186.     /*
  187.     nocliphull(choices) : "Generate clipping hulls" : 0 =
  188.     [
  189.         0 : "Yes"
  190.         1 : "No"
  191.     ]
  192.     */
  193.     iTmp = IntForKey(mapent, "nocliphull");
  194.     if (iTmp == 0)
  195.     {
  196.         g_noclip = true;
  197.     }
  198.     else 
  199.     {
  200.         g_noclip = false;
  201.     }
  202.     Log("%30s [ %-9s ]\n", "Clipping Hull Generation", g_noclip ? "off" : "on");
  203.  
  204.     /*
  205.     noskyclip(choices) : "No Sky Clip" : 0 =
  206.     [
  207.         1 : "On"
  208.         0 : "Off"
  209.     ]
  210.     */
  211.     iTmp = IntForKey(mapent, "noskyclip");
  212.     if (iTmp == 1)
  213.     {
  214.         g_skyclip = false;
  215.     }
  216.     else 
  217.     {
  218.         g_skyclip = true;
  219.     }
  220.     Log("%30s [ %-9s ]\n", "Sky brush clip generation", g_skyclip ? "on" : "off");
  221.  
  222.     ///////////////
  223.     Log("\n");
  224. }
  225. #endif
  226.  
  227. // =====================================================================================
  228. //  NewFaceFromFace
  229. //      Duplicates the non point information of a face, used by SplitFace
  230. // =====================================================================================
  231. bface_t*        NewFaceFromFace(const bface_t* const in)
  232. {
  233.     bface_t*        newf;
  234.  
  235.     newf = (bface_t*)Alloc(sizeof(bface_t));
  236.  
  237.     newf->contents = in->contents;
  238.     newf->texinfo = in->texinfo;
  239.     newf->planenum = in->planenum;
  240.     newf->plane = in->plane;
  241.  
  242.     return newf;
  243. }
  244.  
  245. // =====================================================================================
  246. //  FreeFace
  247. // =====================================================================================
  248. void            FreeFace(bface_t* f)
  249. {
  250.     delete f->w;
  251.     Free(f);
  252. }
  253.  
  254. // =====================================================================================
  255. //  ClipFace
  256. //      Clips a faces by a plane, returning the fragment on the backside and adding any 
  257. //      fragment to the outside.
  258. //      Faces exactly on the plane will stay inside unless overdrawn by later brush.
  259. //      Frontside is the side of the plane that holds the outside list.
  260. //      Precedence is necesary to handle overlapping coplanar faces.
  261. #define    SPLIT_EPSILON    0.3
  262. // =====================================================================================
  263. static bface_t* ClipFace(bface_t* f, bface_t** outside, const int splitplane, const bool precedence)
  264. {
  265.     bface_t*        front;  // clip face
  266.     Winding*        fw;     // forward wind
  267.     Winding*        bw;     // back wind
  268.     plane_t*        split; // plane to clip on
  269.  
  270.     // handle exact plane matches special
  271.  
  272.     if (f->planenum == (splitplane ^ 1)) 
  273.         return f;    // opposite side, so put on inside list
  274.  
  275.     if (f->planenum == splitplane)  // coplanar
  276.     {       
  277.         // this fragment will go to the inside, because
  278.         //   the earlier one was clipped to the outside
  279.         if (precedence)
  280.             return f;
  281.  
  282.         f->next = *outside;
  283.         *outside = f;
  284.         return NULL;
  285.     }
  286.  
  287.     split = &g_mapplanes[splitplane];
  288.     f->w->Clip(split->normal, split->dist, &fw, &bw);
  289.  
  290.     if (!fw)
  291.     {
  292.         delete bw;
  293.         return f;
  294.     }
  295.     else if (!bw)
  296.     {
  297.         delete fw;
  298.         f->next = *outside;
  299.         *outside = f;
  300.         return NULL;
  301.     }
  302.     else
  303.     {
  304.         delete f->w;
  305.     
  306.         front = NewFaceFromFace(f);
  307.         front->w = fw;
  308.         fw->getBounds(front->bounds);
  309.         front->next = *outside;
  310.         *outside = front;
  311.     
  312.         f->w = bw;
  313.         bw->getBounds(f->bounds);
  314.     
  315.         return f;
  316.     }
  317. }
  318.  
  319. // =====================================================================================
  320. //  WriteFace
  321. // =====================================================================================
  322. void            WriteFace(const int hull, const bface_t* const f)
  323. {
  324.     unsigned int    i;
  325.     Winding*        w;
  326.  
  327.     ThreadLock();
  328.     if (!hull)
  329.         c_csgfaces++;
  330.  
  331.     // .p0 format
  332.     w = f->w;
  333.  
  334.     // plane summary
  335.     fprintf(out[hull], "%i %i %i %u\n", f->planenum, f->texinfo, f->contents, w->m_NumPoints);
  336.  
  337.     // for each of the points on the face
  338.     for (i = 0; i < w->m_NumPoints; i++)
  339.     {
  340.         // write the co-ords
  341.         fprintf(out[hull], "%5.2f %5.2f %5.2f\n", w->m_Points[i][0], w->m_Points[i][1], w->m_Points[i][2]);
  342.     }
  343.  
  344.     // put in an extra line break
  345.     fprintf(out[hull], "\n");
  346.  
  347.     ThreadUnlock();
  348. }
  349.  
  350. // =====================================================================================
  351. //  SaveOutside
  352. //      The faces remaining on the outside list are final polygons.  Write them to the 
  353. //      output file.
  354. //      Passable contents (water, lava, etc) will generate a mirrored copy of the face 
  355. //      to be seen from the inside.
  356. // =====================================================================================
  357. static void     SaveOutside(const brush_t* const b, const int hull, bface_t* outside, const int mirrorcontents)
  358. {
  359.     bface_t*        f;
  360.     bface_t*        f2;
  361.     bface_t*        next;
  362.     int             i;
  363.     vec3_t          temp;
  364.  
  365.     for (f = outside; f; f = next)
  366.     {
  367.         next = f->next;
  368.  
  369.         if (f->w->getArea() < g_tiny_threshold)
  370.         {
  371.             c_tiny++;
  372.             Verbose("Entity %i, Brush %i: tiny fragment\n", b->entitynum, b->brushnum);
  373.             continue;
  374.         }
  375.  
  376.         // count unique faces
  377.         if (!hull)
  378.         {
  379.             for (f2 = b->hulls[hull].faces; f2; f2 = f2->next)
  380.             {
  381.                 if (f2->planenum == f->planenum)
  382.                 {
  383.                     if (!f2->used)
  384.                     {
  385.                         f2->used = true;
  386.                         c_outfaces++;
  387.                     }
  388.                     break;
  389.                 }
  390.             }
  391.         }
  392.  
  393.         WriteFace(hull, f);
  394.  
  395.         //              if (mirrorcontents != CONTENTS_SOLID)
  396.         {
  397.             f->planenum ^= 1;
  398.             f->plane = &g_mapplanes[f->planenum];
  399.             f->contents = mirrorcontents;
  400.  
  401.             // swap point orders
  402.             for (i = 0; i < f->w->m_NumPoints / 2; i++)      // add points backwards
  403.             {
  404.                 VectorCopy(f->w->m_Points[i], temp);
  405.                 VectorCopy(f->w->m_Points[f->w->m_NumPoints - 1 - i], f->w->m_Points[i]);
  406.                 VectorCopy(temp, f->w->m_Points[f->w->m_NumPoints - 1 - i]);
  407.             }
  408.             WriteFace(hull, f);
  409.         }
  410.  
  411.         FreeFace(f);
  412.     }
  413. }
  414.  
  415. // =====================================================================================
  416. //  CopyFace
  417. // =====================================================================================
  418. bface_t*        CopyFace(const bface_t* const f)
  419. {
  420.     bface_t*        n;
  421.  
  422.     n = NewFaceFromFace(f);
  423.     n->w = f->w->Copy();
  424.     n->bounds = f->bounds;
  425.     return n;
  426. }
  427.  
  428. // =====================================================================================
  429. //  CopyFaceList
  430. // =====================================================================================
  431. bface_t*        CopyFaceList(bface_t* f)
  432. {
  433.     bface_t*        head;
  434.     bface_t*        n;
  435.  
  436.     if (f)
  437.     {
  438.         head = CopyFace(f);
  439.         n = head;
  440.         f = f->next;
  441.  
  442.         while (f)
  443.         {
  444.             n->next = CopyFace(f);
  445.  
  446.             n = n->next;
  447.             f = f->next;
  448.         }
  449.  
  450.         return head;
  451.     }
  452.     else
  453.     {
  454.         return NULL;
  455.     }
  456. }
  457.  
  458. // =====================================================================================
  459. //  FreeFaceList
  460. // =====================================================================================
  461. void            FreeFaceList(bface_t* f)
  462. {
  463.     if (f)
  464.     {
  465.         if (f->next)
  466.         {
  467.             FreeFaceList(f->next);
  468.         }
  469.         FreeFace(f);
  470.     }
  471. }
  472.  
  473. // =====================================================================================
  474. //  CopyFacesToOutside
  475. //      Make a copy of all the faces of the brush, so they can be chewed up by other 
  476. //      brushes.
  477. //      All of the faces start on the outside list.
  478. //      As other brushes take bites out of the faces, the fragments are moved to the 
  479. //      inside list, so they can be freed when they are determined to be completely 
  480. //      enclosed in solid.
  481. // =====================================================================================
  482. static bface_t* CopyFacesToOutside(brushhull_t* bh)
  483. {
  484.     bface_t*        f;
  485.     bface_t*        newf;
  486.     bface_t*        outside;
  487.  
  488.     outside = NULL;
  489.  
  490.     for (f = bh->faces; f; f = f->next)
  491.     {
  492.         newf = CopyFace(f);
  493.         newf->w->getBounds(newf->bounds);
  494.         newf->next = outside;
  495.         outside = newf;
  496.     }
  497.  
  498.     return outside;
  499. }
  500.  
  501. // =====================================================================================
  502. //  CSGBrush
  503. // =====================================================================================
  504. static void     CSGBrush(int brushnum)
  505. {
  506.     int             hull;
  507.     brush_t*        b1;
  508.     brush_t*        b2;
  509.     brushhull_t*    bh1;
  510.     brushhull_t*    bh2;
  511.     int             bn;
  512.     bool            overwrite;
  513.     bface_t*        f;
  514.     bface_t*        f2;
  515.     bface_t*        next;
  516.     bface_t*        fcopy;
  517.     bface_t*        outside;
  518.     bface_t*        oldoutside;
  519.     entity_t*       e;
  520.     vec_t           area;
  521.  
  522.     // get entity and brush info from the given brushnum that we can work with
  523.     b1 = &g_mapbrushes[brushnum];
  524.     e = &g_entities[b1->entitynum];
  525.  
  526.     // for each of the hulls
  527.     for (hull = 0; hull < NUM_HULLS; hull++)
  528.     {
  529.         bh1 = &b1->hulls[hull];
  530.  
  531.         // set outside to a copy of the brush's faces
  532.         outside = CopyFacesToOutside(bh1);
  533.         overwrite = false;
  534.  
  535.         // for each brush in entity e
  536.         for (bn = 0; bn < e->numbrushes; bn++)
  537.         {
  538.             // see if b2 needs to clip a chunk out of b1
  539.             if (bn == brushnum)  
  540.             {
  541.                 overwrite = true;                          // later brushes now overwrite
  542.                 continue;
  543.             }
  544.  
  545.             b2 = &g_mapbrushes[e->firstbrush + bn];
  546.             bh2 = &b2->hulls[hull];
  547.  
  548.             if (!bh2->faces)
  549.                 continue;                                  // brush isn't in this hull
  550.  
  551.             // check brush bounding box first
  552.             // TODO: use boundingbox method instead
  553.             if (bh1->bounds.testDisjoint(bh2->bounds))
  554.             {
  555.                 continue;
  556.             }
  557.  
  558.             // divide faces by the planes of the b2 to find which
  559.             // fragments are inside
  560.  
  561.             f = outside;
  562.             outside = NULL;
  563.             for (; f; f = next)
  564.             {
  565.                 next = f->next;
  566.  
  567.                 // check face bounding box first
  568.                 if (bh2->bounds.testDisjoint(f->bounds))
  569.                 {                                          // this face doesn't intersect brush2's bbox
  570.                     f->next = outside;
  571.                     outside = f;
  572.                     continue;
  573.                 }
  574.  
  575.                 oldoutside = outside;
  576.                 fcopy = CopyFace(f);                       // save to avoid fake splits
  577.  
  578.                 // throw pieces on the front sides of the planes
  579.                 // into the outside list, return the remains on the inside
  580.                 for (f2 = bh2->faces; f2 && f; f2 = f2->next)
  581.                 {
  582.                     f = ClipFace(f, &outside, f2->planenum, overwrite);
  583.                 }
  584.  
  585.                 area = f ? f->w->getArea() : 0;
  586.                 if (f && area < g_tiny_threshold)
  587.                 {
  588.                     Verbose("Entity %i, Brush %i: tiny penetration\n", b1->entitynum, b1->brushnum);
  589.                     c_tiny_clip++;
  590.                     FreeFace(f);
  591.                     f = NULL;
  592.                 }
  593.                 if (f)
  594.                 {
  595.                     // there is one convex fragment of the original
  596.                     // face left inside brush2
  597.                     FreeFace(fcopy);
  598.  
  599.                     if (b1->contents > b2->contents)
  600.                     {                                      // inside a water brush
  601.                         f->contents = b2->contents;
  602.                         f->next = outside;
  603.                         outside = f;
  604.                     }
  605.                     else                                   // inside a solid brush
  606.                     {
  607.                         FreeFace(f);                       // throw it away
  608.                     }
  609.                 }
  610.                 else
  611.                 {                                          // the entire thing was on the outside, even
  612.                     // though the bounding boxes intersected,
  613.                     // which will never happen with axial planes
  614.  
  615.                     // free the fragments chopped to the outside
  616.                     while (outside != oldoutside)
  617.                     {
  618.                         f2 = outside->next;
  619.                         FreeFace(outside);
  620.                         outside = f2;
  621.                     }
  622.  
  623.                     // revert to the original face to avoid
  624.                     // unneeded false cuts
  625.                     fcopy->next = outside;
  626.                     outside = fcopy;
  627.                 }
  628.             }
  629.  
  630.         }
  631.  
  632.         // all of the faces left in outside are real surface faces
  633.         SaveOutside(b1, hull, outside, b1->contents);
  634.     }
  635. }
  636.  
  637. //
  638. // =====================================================================================
  639. //
  640.  
  641. // =====================================================================================
  642. //  EmitPlanes
  643. // =====================================================================================
  644. static void     EmitPlanes()
  645. {
  646.     int             i;
  647.     dplane_t*       dp;
  648.     plane_t*        mp;
  649.  
  650.     g_numplanes = g_nummapplanes;
  651.     mp = g_mapplanes;
  652.     dp = g_dplanes;
  653.     for (i = 0; i < g_nummapplanes; i++, mp++, dp++)
  654.     {
  655.         //if (!(mp->redundant))
  656.         //{
  657.         //    Log("EmitPlanes: plane %i non redundant\n", i);
  658.             VectorCopy(mp->normal, dp->normal);
  659.             dp->dist = mp->dist;
  660.             dp->type = mp->type;
  661.        // }
  662.         //else
  663.        // {
  664.        //     Log("EmitPlanes: plane %i redundant\n", i);
  665.        // }
  666.     }
  667. }
  668.  
  669. // =====================================================================================
  670. //  SetModelNumbers
  671. //      blah
  672. // =====================================================================================
  673. static void     SetModelNumbers()
  674. {
  675.     int             i;
  676.     int             models;
  677.     char            value[10];
  678.  
  679.     models = 1;
  680.     for (i = 1; i < g_numentities; i++)
  681.     {
  682.         if (g_entities[i].numbrushes)
  683.         {
  684.             safe_snprintf(value, sizeof(value), "*%i", models);
  685.             models++;
  686.             SetKeyValue(&g_entities[i], "model", value);
  687.         }
  688.     }
  689. }
  690.  
  691. // =====================================================================================
  692. //  SetLightStyles
  693. // =====================================================================================
  694. #define    MAX_SWITCHED_LIGHTS        32 
  695. #define MAX_LIGHTTARGETS_NAME   64
  696.  
  697. static void     SetLightStyles()
  698. {
  699.     int             stylenum;
  700.     const char*     t;
  701.     entity_t*       e;
  702.     int             i, j;
  703.     char            value[10];
  704.     char            lighttargets[MAX_SWITCHED_LIGHTS][MAX_LIGHTTARGETS_NAME];
  705.  
  706. #ifdef ZHLT_TEXLIGHT
  707.         bool            newtexlight = false;
  708. #endif
  709.  
  710.     // any light that is controlled (has a targetname)
  711.     // must have a unique style number generated for it
  712.  
  713.     stylenum = 0;
  714.     for (i = 1; i < g_numentities; i++)
  715.     {
  716.         e = &g_entities[i];
  717.  
  718.         t = ValueForKey(e, "classname");
  719.         if (strncasecmp(t, "light", 5))
  720.         {
  721. #ifdef ZHLT_TEXLIGHT
  722.             //LRC:
  723.             // if it's not a normal light entity, allocate it a new style if necessary.
  724.             t = ValueForKey(e, "style");
  725.             switch (atoi(t))
  726.             {
  727.             case 0: // not a light, no style, generally pretty boring
  728.                 continue;
  729.             case -1: // normal switchable texlight
  730.                 safe_snprintf(value, sizeof(value), "%i", 32 + stylenum);
  731.                 SetKeyValue(e, "style", value);
  732.                 stylenum++;
  733.                 continue;
  734.             case -2: // backwards switchable texlight
  735.                 safe_snprintf(value, sizeof(value), "%i", -(32 + stylenum));
  736.                 SetKeyValue(e, "style", value);
  737.                 stylenum++;
  738.                 continue;
  739.             case -3: // (HACK) a piggyback texlight: switched on and off by triggering a real light that has the same name
  740.                 SetKeyValue(e, "style", "0"); // just in case the level designer didn't give it a name
  741.                 newtexlight = true;
  742.                 // don't 'continue', fall out
  743.             }
  744.             //LRC (ends)
  745. #else
  746.             continue;
  747. #endif
  748.         }
  749.         t = ValueForKey(e, "targetname");
  750.         if (!t[0])
  751.         {
  752.             continue;
  753.         }
  754.  
  755.         // find this targetname
  756.         for (j = 0; j < stylenum; j++)
  757.         {
  758.             if (!strcmp(lighttargets[j], t))
  759.             {
  760.                 break;
  761.             }
  762.         }
  763.         if (j == stylenum)
  764.         {
  765.             hlassume(stylenum < MAX_SWITCHED_LIGHTS, assume_MAX_SWITCHED_LIGHTS);
  766.             safe_strncpy(lighttargets[j], t, MAX_LIGHTTARGETS_NAME);
  767.             stylenum++;
  768.         }
  769.         safe_snprintf(value, sizeof(value), "%i", 32 + j);
  770.         SetKeyValue(e, "style", value);
  771.     }
  772.  
  773. }
  774.  
  775. // =====================================================================================
  776. //  ConvertHintToEmtpy
  777. // =====================================================================================
  778. static void     ConvertHintToEmpty()
  779. {
  780.     int             i;
  781.  
  782.     // Convert HINT brushes to EMPTY after they have been carved by csg
  783.     for (i = 0; i < MAX_MAP_BRUSHES; i++)
  784.     {
  785.         if (g_mapbrushes[i].contents == CONTENTS_HINT)
  786.         {
  787.             g_mapbrushes[i].contents = CONTENTS_EMPTY;
  788.         }
  789.     }
  790. }
  791.  
  792. // =====================================================================================
  793. //  WriteBSP
  794. // =====================================================================================
  795. void            WriteBSP(const char* const name)
  796. {
  797.     char            path[_MAX_PATH];
  798.  
  799.     safe_strncpy(path, name, _MAX_PATH);
  800.     DefaultExtension(path, ".bsp");
  801.  
  802.     SetModelNumbers();
  803.     SetLightStyles();
  804.  
  805.     if (!g_onlyents)
  806.         WriteMiptex();
  807.  
  808.     UnparseEntities();
  809.     ConvertHintToEmpty();
  810.     WriteBSPFile(path);
  811. }
  812.  
  813. //
  814. // =====================================================================================
  815. //
  816.  
  817. // AJM: added in function
  818. // =====================================================================================
  819. //  CopyGenerictoCLIP
  820. //      clips a generic brush
  821. // =====================================================================================
  822. static void     CopyGenerictoCLIP(const brush_t* const b)
  823. {
  824.     // code blatently ripped from CopySKYtoCLIP()
  825.  
  826.     int             i;
  827.     entity_t*       mapent;
  828.     brush_t*        newbrush;
  829.  
  830.     mapent = &g_entities[b->entitynum];
  831.     mapent->numbrushes++;
  832.  
  833.     newbrush = &g_mapbrushes[g_nummapbrushes];
  834.     newbrush->entitynum = b->entitynum;
  835.     newbrush->brushnum = g_nummapbrushes - mapent->firstbrush;
  836.     newbrush->firstside = g_numbrushsides;
  837.     newbrush->numsides = b->numsides;
  838.     newbrush->contents = CONTENTS_CLIP;
  839.     newbrush->noclip = 0;
  840.  
  841.     for (i = 0; i < b->numsides; i++)
  842.     {
  843.         int             j;
  844.  
  845.         side_t*         side = &g_brushsides[g_numbrushsides];
  846.  
  847.         *side = g_brushsides[b->firstside + i];
  848.         safe_strncpy(side->td.name, "CLIP", sizeof(side->td.name));
  849.  
  850.         for (j = 0; j < NUM_HULLS; j++)
  851.         {
  852.             newbrush->hulls[j].faces = NULL;
  853.             newbrush->hulls[j].bounds = b->hulls[j].bounds;
  854.         }
  855.  
  856.         g_numbrushsides++;
  857.         hlassume(g_numbrushsides < MAX_MAP_SIDES, assume_MAX_MAP_SIDES);
  858.     }
  859.  
  860.     g_nummapbrushes++;
  861.     hlassume(g_nummapbrushes < MAX_MAP_BRUSHES, assume_MAX_MAP_BRUSHES);
  862. }
  863.  
  864. #ifdef HLCSG_CLIPECONOMY
  865. // AJM: added in 
  866. unsigned int    BrushClipHullsDiscarded = 0; 
  867. unsigned int    ClipNodesDiscarded = 0;
  868.  
  869. //AJM: added in function
  870. static void     MarkEntForNoclip(entity_t*  ent)
  871. {
  872.     int             i;
  873.     brush_t*        b;
  874.  
  875.     for (i = ent->firstbrush; i < ent->firstbrush + ent->numbrushes; i++)
  876.     {
  877.         b = &g_mapbrushes[i];
  878.         b->noclip = 1;  
  879.  
  880.         BrushClipHullsDiscarded++;
  881.         ClipNodesDiscarded += b->numsides;
  882.     }
  883. }
  884.  
  885. // AJM
  886. // =====================================================================================
  887. //  CheckForNoClip
  888. //      marks the noclip flag on any brushes that dont need clipnode generation, eg. func_illusionaries
  889. // =====================================================================================
  890. static void     CheckForNoClip()
  891. {
  892.     int             i;
  893.     entity_t*       ent;
  894.  
  895.     char            entclassname[MAX_KEY]; 
  896.     int             spawnflags;
  897.  
  898.     if (!g_bClipNazi) 
  899.         return; // NO CLIP FOR YOU!!!
  900.  
  901.     for (i = 0; i < g_numentities; i++)
  902.     {
  903.         if (!g_entities[i].numbrushes) 
  904.             continue; // not a model
  905.  
  906.         if (!i) 
  907.             continue; // dont waste our time with worldspawn
  908.  
  909.         ent = &g_entities[i];
  910.  
  911.         strcpy(entclassname, ValueForKey(ent, "classname"));
  912.         spawnflags = atoi(ValueForKey(ent, "spawnflags"));
  913.  
  914.         // condition 1, its a func_illusionary 
  915.         if (!strncasecmp(entclassname,      "func_illusionary", 16))  
  916.         {
  917.             MarkEntForNoclip(ent);
  918.         }
  919.         // condition 2, flag 4 (8) is set and it is either a func_door, func_train, momentary_door, 
  920.         //  func_door_rotating or func_tracktrain (passable, not-solid flag )        
  921.         else if (    (spawnflags & 8)
  922.                      && 
  923.                      (   /* NOTE: func_doors as far as i can tell may need clipnodes for their
  924.                             player collision detection, so for now, they stay out of it. */
  925.                           (!strncasecmp(entclassname, "func_train",         10))
  926.                        || (!strncasecmp(entclassname, "func_door",           9)) 
  927.                   //   || (!strncasecmp(entclassname, "momentary_door",     14))
  928.                   //   || (!strncasecmp(entclassname, "func_door_rotating", 18))
  929.                        || (!strncasecmp(entclassname, "func_tracktrain",    15))
  930.                      )
  931.                 ) 
  932.         {
  933.             MarkEntForNoclip(ent);
  934.         } 
  935.         // condition 3: flag 2 (2) is set, and its a func_conveyor (not solid flag)  
  936.         else if ( (spawnflags & 2) && (!strncasecmp(entclassname, "func_conveyor", 13)) ) 
  937.         {
  938.             MarkEntForNoclip(ent);
  939.         }
  940.         // condition 4: flag 1 (1) is set, and its a func_rot_button (not solid flag)     
  941.         else if ( (spawnflags & 1) && (!strncasecmp(entclassname, "func_rot_button", 15)) )
  942.         {
  943.             MarkEntForNoclip(ent);
  944.         }
  945.         // condition 5: flag 7 (64) is set, and its a func_rotating                     
  946.         else if ( (spawnflags & 64) && (!strncasecmp(entclassname, "func_rotating", 13)) )
  947.         {
  948.             MarkEntForNoclip(ent);
  949.         }            
  950.         /*
  951.         // condition 6: its a func_wall, while we noclip it, we remake the clipnodes manually 
  952.         else if (!strncasecmp(entclassname, "func_wall", 9)) 
  953.         {
  954.             for (int j = ent->firstbrush; j < ent->firstbrush + ent->numbrushes; j++)
  955.                 CopyGenerictoCLIP(&g_mapbrushes[i]);
  956.  
  957.             MarkEntForNoclip(ent);
  958.         }
  959. */
  960.     }
  961.  
  962.     Log("%i brushes (totalling %i sides) discarded from clipping hulls\n", BrushClipHullsDiscarded, ClipNodesDiscarded);
  963. }
  964. #endif
  965.  
  966. // =====================================================================================
  967. //  ProcessModels
  968. // =====================================================================================
  969. #define NUM_TYPECONTENTS    5 // AJM: should reflect the number of values below
  970. int typecontents[NUM_TYPECONTENTS] = { 
  971.     CONTENTS_WATER, CONTENTS_SLIME, CONTENTS_LAVA, CONTENTS_SKY, CONTENTS_HINT 
  972. };
  973.  
  974.  
  975. static void     ProcessModels()
  976. {
  977.     int             i, j, type;
  978.     int             placed;
  979.     int             first, contents;
  980.     brush_t         temp;
  981.  
  982.     for (i = 0; i < g_numentities; i++)
  983.     {
  984.         if (!g_entities[i].numbrushes) // only models
  985.             continue;
  986.  
  987.         // sort the contents down so stone bites water, etc
  988.         first = g_entities[i].firstbrush;
  989.         placed = 0;
  990.         for (type = 0; type < NUM_TYPECONTENTS; type++)                 // for each of the contents types
  991.         {
  992.             contents = typecontents[type];
  993.             for (j = placed + 1; j < g_entities[i].numbrushes; j++)     // for each of the model's brushes
  994.             {
  995.                 // if this brush is of the contents type in this for iteration
  996.                 if (g_mapbrushes[first + j].contents == contents)       
  997.                 {
  998.                     temp = g_mapbrushes[first + placed];
  999.                     g_mapbrushes[first + placed] = g_mapbrushes[j];
  1000.                     g_mapbrushes[j] = temp;
  1001.                     placed++;
  1002.                 }
  1003.             }
  1004.         }
  1005.  
  1006.         // csg them in order
  1007.         if (i == 0) // if its worldspawn....
  1008.         {
  1009.             NamedRunThreadsOnIndividual(g_entities[i].numbrushes, g_estimate, CSGBrush);
  1010.             CheckFatal();
  1011.         }
  1012.         else
  1013.         {
  1014.             for (j = 0; j < g_entities[i].numbrushes; j++)
  1015.             {
  1016.                 CSGBrush(first + j);
  1017.             }
  1018.         }
  1019.  
  1020.         // write end of model marker
  1021.         for (j = 0; j < NUM_HULLS; j++)
  1022.         {
  1023.             fprintf(out[j], "-1 -1 -1 -1\n");
  1024.         }
  1025.     }
  1026. }
  1027.  
  1028. // =====================================================================================
  1029. //  SetModelCenters
  1030. // =====================================================================================
  1031. static void     SetModelCenters(int entitynum)
  1032. {
  1033.     int             i;
  1034.     int             last;
  1035.     char            string[MAXTOKEN];
  1036.     entity_t*       e = &g_entities[entitynum];
  1037.     BoundingBox     bounds;
  1038.     vec3_t          center;
  1039.  
  1040.     if ((entitynum == 0) || (e->numbrushes == 0)) // skip worldspawn and point entities
  1041.         return;
  1042.  
  1043.     if (!*ValueForKey(e, "light_origin")) // skip if its not a zhlt_flags light_origin
  1044.         return;
  1045.  
  1046.     for (i = e->firstbrush, last = e->firstbrush + e->numbrushes; i < last; i++)
  1047.     {
  1048.         if (g_mapbrushes[i].contents != CONTENTS_ORIGIN)
  1049.         {
  1050.             bounds.add(g_mapbrushes[i].hulls->bounds);
  1051.         }
  1052.     }
  1053.  
  1054.     VectorAdd(bounds.m_Mins, bounds.m_Maxs, center);
  1055.     VectorScale(center, 0.5, center);
  1056.  
  1057.     safe_snprintf(string, MAXTOKEN, "%i %i %i", (int)center[0], (int)center[1], (int)center[2]);
  1058.     SetKeyValue(e, "model_center", string);
  1059. }
  1060.  
  1061. //
  1062. // =====================================================================================
  1063. //
  1064.  
  1065. // =====================================================================================
  1066. //  BoundWorld
  1067. // =====================================================================================
  1068. static void     BoundWorld()
  1069. {
  1070.     int             i;
  1071.     brushhull_t*    h;
  1072.  
  1073.     world_bounds.reset();
  1074.  
  1075.     for (i = 0; i < g_nummapbrushes; i++)
  1076.     {
  1077.         h = &g_mapbrushes[i].hulls[0];
  1078.         if (!h->faces)
  1079.         {
  1080.             continue;
  1081.         }
  1082.         world_bounds.add(h->bounds);
  1083.     }
  1084.  
  1085.     Verbose("World bounds: (%i %i %i) to (%i %i %i)\n",
  1086.             (int)world_bounds.m_Mins[0], (int)world_bounds.m_Mins[1], (int)world_bounds.m_Mins[2],
  1087.             (int)world_bounds.m_Maxs[0], (int)world_bounds.m_Maxs[1], (int)world_bounds.m_Maxs[2]);
  1088. }
  1089.  
  1090. // =====================================================================================
  1091. //  Usage
  1092. //      prints out usage sheet
  1093. // =====================================================================================
  1094. static void     Usage()
  1095. {
  1096.     Banner(); // TODO: Call banner from main CSG process? 
  1097.  
  1098.     Log("\n-= %s Options =-\n\n", g_Program);
  1099.     Log("    -nowadtextures   : include all used textures into bsp\n");
  1100.     Log("    -wadinclude file : place textures used from wad specified into bsp\n");
  1101.     Log("    -noclip          : don't create clipping hull\n");
  1102.     
  1103. #ifdef HLCSG_CLIPECONOMY    // AJM
  1104.     Log("    -noclipeconomy   : turn clipnode economy mode off\n");
  1105. #endif
  1106.  
  1107.     Log("    -onlyents        : do an entity update from .map to .bsp\n");
  1108.     Log("    -noskyclip       : disable automatic clipping of SKY brushes\n");
  1109.     Log("    -tiny #          : minmum brush face surface area before it is discarded\n");
  1110.     Log("    -brushunion #    : threshold to warn about overlapping brushes\n\n");
  1111.     Log("    -hullfile file   : Reads in custom collision hull dimensions\n");
  1112.     Log("    -texdata #       : Alter maximum texture memory limit (in kb)\n");
  1113.     Log("    -chart           : display bsp statitics\n");
  1114.     Log("    -low | -high     : run program an altered priority level\n");
  1115.     Log("    -nolog           : don't generate the compile logfiles\n");
  1116.     Log("    -threads #       : manually specify the number of threads to run\n");
  1117. #ifdef SYSTEM_WIN32
  1118.     Log("    -estimate        : display estimated time during compile\n");
  1119. #endif
  1120. #ifdef ZHLT_PROGRESSFILE // AJM
  1121.     Log("    -progressfile path  : specify the path to a file for progress estimate output\n");
  1122. #endif
  1123. #ifdef SYSTEM_POSIX
  1124.     Log("    -noestimate      : do not display continuous compile time estimates\n");
  1125. #endif
  1126.     Log("    -verbose         : compile with verbose messages\n");
  1127.     Log("    -noinfo          : Do not show tool configuration information\n");
  1128.  
  1129. #ifdef ZHLT_NULLTEX // AJM
  1130.     Log("    -nonulltex       : Turns off null texture stripping\n");
  1131. #endif
  1132.  
  1133. #ifdef ZHLT_DETAIL // AJM
  1134.     Log("    -nodetail        : dont handle detail brushes\n");
  1135. #endif
  1136.  
  1137.     Log("    -dev #           : compile with developer message\n\n");
  1138.  
  1139. #ifdef HLCSG_WADCFG // AJM
  1140.     Log("    -wadconfig name  : Specify a configuration to use from wad.cfg\n");
  1141.     Log("    -wadcfgfile path : Manually specify a path to the wad.cfg file\n"); //JK:
  1142. #endif
  1143.  
  1144. #ifdef HLCSG_AUTOWAD // AJM:
  1145.     Log("    -wadautodetect   : Force auto-detection of wadfiles\n");
  1146. #endif
  1147.     Log("    mapfile          : The mapfile to compile\n\n");
  1148.  
  1149.     exit(1);
  1150. }
  1151.  
  1152. // =====================================================================================
  1153. //  DumpWadinclude
  1154. //      prints out the wadinclude list
  1155. // =====================================================================================
  1156. static void     DumpWadinclude()
  1157. {
  1158.     Log("Wadinclude list :\n");
  1159.     WadInclude_i it;
  1160.     for (it = g_WadInclude.begin(); it != g_WadInclude.end(); it++)
  1161.     {
  1162.         Log("[%s]\n", it->c_str());
  1163.     }
  1164. }
  1165.  
  1166. // =====================================================================================
  1167. //  Settings
  1168. //      prints out settings sheet
  1169. // =====================================================================================
  1170. static void     Settings()
  1171. {
  1172.     char*           tmp;
  1173.  
  1174.     if (!g_info)
  1175.         return; 
  1176.  
  1177.     Log("\nCurrent %s Settings\n", g_Program);
  1178.     Log("Name                 |  Setting  |  Default\n"
  1179.         "---------------------|-----------|-------------------------\n");
  1180.  
  1181.     // ZHLT Common Settings
  1182.     if (DEFAULT_NUMTHREADS == -1)
  1183.     {
  1184.         Log("threads               [ %7d ] [  Varies ]\n", g_numthreads);
  1185.     }
  1186.     else
  1187.     {
  1188.         Log("threads               [ %7d ] [ %7d ]\n", g_numthreads, DEFAULT_NUMTHREADS);
  1189.     }
  1190.  
  1191.     Log("verbose               [ %7s ] [ %7s ]\n", g_verbose ? "on" : "off", DEFAULT_VERBOSE ? "on" : "off");
  1192.     Log("log                   [ %7s ] [ %7s ]\n", g_log ? "on" : "off", DEFAULT_LOG ? "on" : "off");
  1193.  
  1194.     Log("developer             [ %7d ] [ %7d ]\n", g_developer, DEFAULT_DEVELOPER);
  1195.     Log("chart                 [ %7s ] [ %7s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off");
  1196.     Log("estimate              [ %7s ] [ %7s ]\n", g_estimate ? "on" : "off", DEFAULT_ESTIMATE ? "on" : "off");
  1197.     Log("max texture memory    [ %7d ] [ %7d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX);
  1198.  
  1199.     switch (g_threadpriority)
  1200.     {
  1201.     case eThreadPriorityNormal:
  1202.     default:
  1203.         tmp = "Normal";
  1204.         break;
  1205.     case eThreadPriorityLow:
  1206.         tmp = "Low";
  1207.         break;
  1208.     case eThreadPriorityHigh:
  1209.         tmp = "High";
  1210.         break;
  1211.     }
  1212.     Log("priority              [ %7s ] [ %7s ]\n", tmp, "Normal");
  1213.     Log("\n");
  1214.  
  1215.     // HLCSG Specific Settings
  1216.  
  1217.     Log("noclip                [ %7s ] [ %7s ]\n", g_noclip          ? "on" : "off", DEFAULT_NOCLIP       ? "on" : "off");
  1218.  
  1219. #ifdef ZHLT_NULLTEX // AJM:
  1220.     Log("null texture stripping[ %7s ] [ %7s ]\n", g_bUseNullTex     ? "on" : "off", DEFAULT_NULLTEX      ? "on" : "off");
  1221. #endif
  1222.  
  1223. #ifdef ZHLT_DETAIL // AJM
  1224.     Log("detail brushes        [ %7s ] [ %7s ]\n", g_bDetailBrushes  ? "on" : "off", DEFAULT_DETAIL       ? "on" : "off");
  1225. #endif
  1226.  
  1227. #ifdef HLCSG_CLIPECONOMY // AJM
  1228.     Log("clipnode economy mode [ %7s ] [ %7s ]\n", g_bClipNazi       ? "on" : "off", DEFAULT_CLIPNAZI     ? "on" : "off");
  1229. #endif
  1230.  
  1231.     Log("onlyents              [ %7s ] [ %7s ]\n", g_onlyents        ? "on" : "off", DEFAULT_ONLYENTS     ? "on" : "off");
  1232.     Log("wadtextures           [ %7s ] [ %7s ]\n", g_wadtextures     ? "on" : "off", DEFAULT_WADTEXTURES  ? "on" : "off");
  1233.     Log("skyclip               [ %7s ] [ %7s ]\n", g_skyclip         ? "on" : "off", DEFAULT_SKYCLIP      ? "on" : "off");
  1234.     Log("hullfile              [ %7s ] [ %7s ]\n", g_hullfile ? g_hullfile : "None", "None");
  1235.  
  1236.     // calc min surface area
  1237.     {
  1238.         char            tiny_penetration[10];
  1239.         char            default_tiny_penetration[10];
  1240.  
  1241.         safe_snprintf(tiny_penetration, sizeof(tiny_penetration), "%3.3f", g_tiny_threshold);
  1242.         safe_snprintf(default_tiny_penetration, sizeof(default_tiny_penetration), "%3.3f", DEFAULT_TINY_THRESHOLD);
  1243.         Log("min surface area      [ %7s ] [ %7s ]\n", tiny_penetration, default_tiny_penetration);
  1244.     }
  1245.  
  1246.     // calc union threshold
  1247.     {
  1248.         char            brush_union[10];
  1249.         char            default_brush_union[10];
  1250.  
  1251.         safe_snprintf(brush_union, sizeof(brush_union), "%3.3f", g_BrushUnionThreshold);
  1252.         safe_snprintf(default_brush_union, sizeof(default_brush_union), "%3.3f", DEFAULT_BRUSH_UNION_THRESHOLD);
  1253.         Log("brush union threshold [ %7s ] [ %7s ]\n", brush_union, default_brush_union);
  1254.     }
  1255.  
  1256.     Log("\n");
  1257. }
  1258.  
  1259. // AJM: added in
  1260. // =====================================================================================
  1261. //  CSGCleanup
  1262. // =====================================================================================
  1263. void            CSGCleanup()
  1264. {
  1265.     //Log("CSGCleanup\n");
  1266. #ifdef HLCSG_AUTOWAD
  1267.     autowad_cleanup();
  1268. #endif
  1269. #ifdef HLCSG_WADCFG
  1270.     WadCfg_cleanup();
  1271. #endif
  1272.     FreeWadPaths();
  1273. }
  1274.  
  1275. // =====================================================================================
  1276. //  Main
  1277. //      Oh, come on.
  1278. // =====================================================================================
  1279. int             main(const int argc, char** argv)
  1280. {
  1281.     int             i;                          
  1282.     char            name[_MAX_PATH];            // mapanme 
  1283.     double          start, end;                 // start/end time log
  1284.     const char*     mapname_from_arg = NULL;    // mapname path from passed argvar
  1285.  
  1286.     g_Program = "hlcsg";
  1287.  
  1288.     if (argc == 1)
  1289.         Usage();
  1290.  
  1291.     // Hard coded list of -wadinclude files, used for HINT texture brushes so lazy
  1292.     // mapmakers wont cause beta testers (or possibly end users) to get a wad 
  1293.     // error on zhlt.wad etc
  1294.     g_WadInclude.push_back("zhlt.wad");
  1295.  
  1296.     memset(wadconfigname, 0, sizeof(wadconfigname));//AJM
  1297.  
  1298.     // detect argv
  1299.     for (i = 1; i < argc; i++)
  1300.     {
  1301.         if (!strcasecmp(argv[i], "-threads"))
  1302.         {
  1303.             if (i < argc)
  1304.             {
  1305.                 g_numthreads = atoi(argv[++i]);
  1306.                 if (g_numthreads < 1)
  1307.                 {
  1308.                     Log("Expected value of at least 1 for '-threads'\n");
  1309.                     Usage();
  1310.                 }
  1311.             }
  1312.             else
  1313.             {
  1314.                 Usage();
  1315.             }
  1316.         }
  1317.  
  1318. #ifdef SYSTEM_WIN32
  1319.         else if (!strcasecmp(argv[i], "-estimate"))
  1320.         {
  1321.             g_estimate = true;
  1322.         }
  1323. #endif
  1324.  
  1325. #ifdef SYSTEM_POSIX
  1326.         else if (!strcasecmp(argv[i], "-noestimate"))
  1327.         {
  1328.             g_estimate = false;
  1329.         }
  1330. #endif
  1331.  
  1332.         else if (!strcasecmp(argv[i], "-dev"))
  1333.         {
  1334.             if (i < argc)
  1335.             {
  1336.                 g_developer = (developer_level_t)atoi(argv[++i]);
  1337.             }
  1338.             else
  1339.             {
  1340.                 Usage();
  1341.             }
  1342.         }
  1343.         else if (!strcasecmp(argv[i], "-verbose"))
  1344.         {
  1345.             g_verbose = true;
  1346.         }
  1347.         else if (!strcasecmp(argv[i], "-noinfo"))
  1348.         {
  1349.             g_info = false;
  1350.         }
  1351.         else if (!strcasecmp(argv[i], "-chart"))
  1352.         {
  1353.             g_chart = true;
  1354.         }
  1355.         else if (!strcasecmp(argv[i], "-low"))
  1356.         {
  1357.             g_threadpriority = eThreadPriorityLow;
  1358.         }
  1359.         else if (!strcasecmp(argv[i], "-high"))
  1360.         {
  1361.             g_threadpriority = eThreadPriorityHigh;
  1362.         }
  1363.         else if (!strcasecmp(argv[i], "-nolog"))
  1364.         {
  1365.             g_log = false;
  1366.         }
  1367.         else if (!strcasecmp(argv[i], "-skyclip"))
  1368.         {
  1369.             g_skyclip = true;
  1370.         }
  1371.         else if (!strcasecmp(argv[i], "-noskyclip"))
  1372.         {
  1373.             g_skyclip = false;
  1374.         }
  1375.         else if (!strcasecmp(argv[i], "-noclip"))
  1376.         {
  1377.             g_noclip = true;
  1378.         }
  1379.         else if (!strcasecmp(argv[i], "-onlyents"))
  1380.         {
  1381.             g_onlyents = true;
  1382.         }
  1383.  
  1384. #ifdef ZHLT_NULLTEX  // AJM: added in -nonulltex
  1385.         else if (!strcasecmp(argv[i], "-nonulltex"))
  1386.         {
  1387.             g_bUseNullTex = false;
  1388.         }
  1389. #endif
  1390.  
  1391. #ifdef HLCSG_CLIPECONOMY    // AJM: added in -noclipeconomy
  1392.         else if (!strcasecmp(argv[i], "-noclipeconomy"))
  1393.         {
  1394.             g_bClipNazi = false;
  1395.         }
  1396. #endif
  1397.  
  1398. #ifdef HLCSG_WADCFG
  1399.         // AJM: added in -wadconfig
  1400.         else if (!strcasecmp(argv[i], "-wadconfig"))
  1401.         { 
  1402.             if (i < argc)
  1403.             {
  1404.                 safe_strncpy(wadconfigname, argv[++i], MAX_WAD_CFG_NAME);
  1405.                 if (strlen(argv[i]) > MAX_WAD_CFG_NAME)
  1406.                 {
  1407.                     Warning("wad configuration name was truncated to %i chars", MAX_WAD_CFG_NAME);
  1408.                     wadconfigname[MAX_WAD_CFG_NAME] = 0;
  1409.                 }
  1410.             }
  1411.             else
  1412.             {
  1413.                 Log("Error: -wadconfig: incorrect usage of parameter\n");
  1414.                 Usage();
  1415.             }
  1416.         }
  1417.  
  1418.         //JK: added in -wadcfgfile
  1419.         else if (!strcasecmp(argv[i], "-wadcfgfile"))
  1420.         {
  1421.             if (i < argc)
  1422.             {
  1423.                 g_wadcfgfile = argv[++i];
  1424.             }
  1425.             else
  1426.             {
  1427.                 Log("Error: -wadcfgfile: incorrect usage of parameter\n");
  1428.                 Usage();
  1429.             }
  1430.         }
  1431. #endif
  1432.  
  1433. #ifdef HLCSG_AUTOWAD // AJM
  1434.         else if (!strcasecmp(argv[i], "-wadautodetect"))
  1435.         { 
  1436.             g_bWadAutoDetect = true;
  1437.         }
  1438. #endif
  1439.  
  1440. #ifdef ZHLT_DETAIL // AJM
  1441.         else if (!strcasecmp(argv[i], "-nodetail"))
  1442.         {
  1443.             g_bDetailBrushes = false;
  1444.         }
  1445. #endif
  1446.  
  1447. #ifdef ZHLT_PROGRESSFILE // AJM
  1448.         else if (!strcasecmp(argv[i], "-progressfile"))
  1449.         {
  1450.             if (i < argc)
  1451.             {
  1452.                 g_progressfile = argv[++i];
  1453.             }
  1454.             else
  1455.             {
  1456.                 Log("Error: -progressfile: expected path to progress file following parameter\n");
  1457.                 Usage();
  1458.             }
  1459.         }
  1460. #endif
  1461.  
  1462.         else if (!strcasecmp(argv[i], "-nowadtextures"))
  1463.         {
  1464.             g_wadtextures = false;
  1465.         }
  1466.         else if (!strcasecmp(argv[i], "-wadinclude"))
  1467.         {
  1468.             if (i < argc)
  1469.             {
  1470.                 g_WadInclude.push_back(argv[++i]);
  1471.             }
  1472.             else
  1473.             {
  1474.                 Usage();
  1475.             }
  1476.         }
  1477.         else if (!strcasecmp(argv[i], "-texdata"))
  1478.         {
  1479.             if (i < argc)
  1480.             {
  1481.                 int             x = atoi(argv[++i]) * 1024;
  1482.  
  1483.                 if (x > g_max_map_miptex)
  1484.                 {
  1485.                     g_max_map_miptex = x;
  1486.                 }
  1487.             }
  1488.             else
  1489.             {
  1490.                 Usage();
  1491.             }
  1492.         }
  1493.         else if (!strcasecmp(argv[i], "-brushunion"))
  1494.         {
  1495.             if (i < argc)
  1496.             {
  1497.                 g_BrushUnionThreshold = (float)atof(argv[++i]);
  1498.             }
  1499.             else
  1500.             {
  1501.                 Usage();
  1502.             }
  1503.         }
  1504.         else if (!strcasecmp(argv[i], "-tiny"))
  1505.         {
  1506.             if (i < argc)
  1507.             {
  1508.                 g_tiny_threshold = (float)atof(argv[++i]);
  1509.             }
  1510.             else
  1511.             {
  1512.                 Usage();
  1513.             }
  1514.         }
  1515.         else if (!strcasecmp(argv[i], "-hullfile"))
  1516.         {
  1517.             if (i < argc)
  1518.             {
  1519.                 g_hullfile = argv[++i];
  1520.             }
  1521.             else
  1522.             {
  1523.                 Usage();
  1524.             }
  1525.         }
  1526.         else if (argv[i][0] == '-')
  1527.         {
  1528.             Log("Unknown option \"%s\"\n", argv[i]);
  1529.             Usage();
  1530.         }
  1531.         else if (!mapname_from_arg)
  1532.         {
  1533.             mapname_from_arg = argv[i];
  1534.         }
  1535.         else
  1536.         {
  1537.             Log("Unknown option \"%s\"\n", argv[i]);
  1538.             Usage();
  1539.         }
  1540.     }
  1541.  
  1542.     // no mapfile?
  1543.     if (!mapname_from_arg)
  1544.     {
  1545.         // what a shame.
  1546.         Log("No mapfile specified\n");
  1547.         Usage();
  1548.     }
  1549.  
  1550.     // handle mapname
  1551.     safe_strncpy(g_Mapname, mapname_from_arg, _MAX_PATH);
  1552.     FlipSlashes(g_Mapname);
  1553.     StripExtension(g_Mapname);
  1554.  
  1555.     // onlyents
  1556.     if (!g_onlyents)
  1557.         ResetTmpFiles();
  1558.  
  1559.     // other stuff
  1560.     ResetErrorLog();                     
  1561.     ResetLog();                          
  1562.     OpenLog(g_clientid);                  
  1563.     atexit(CloseLog);                       
  1564.     LogStart(argc, argv);                   
  1565.     atexit(CSGCleanup); // AJM
  1566.     dtexdata_init();                        
  1567.     atexit(dtexdata_free);
  1568.  
  1569.     // START CSG
  1570.     // AJM: re-arranged some stuff up here so that the mapfile is loaded
  1571.     //  before settings are finalised and printed out, so that the info_compile_parameters
  1572.     //  entity can be dealt with effectively
  1573.     start = I_FloatTime();
  1574.     
  1575.     LoadHullfile(g_hullfile);               // if the user specified a hull file, load it now
  1576.     safe_strncpy(name, mapname_from_arg, _MAX_PATH); // make a copy of the nap name
  1577.     DefaultExtension(name, ".map");                  // might be .reg
  1578.     
  1579.     LoadMapFile(name);
  1580.     ThreadSetDefault();                    
  1581.     ThreadSetPriority(g_threadpriority);  
  1582.     Settings();
  1583.  
  1584.  
  1585. #ifdef HLCSG_WADCFG // AJM
  1586.     // figure out what to do with the texture settings
  1587.     if (wadconfigname[0])           // custom wad configuations will take precedence
  1588.     {
  1589.         LoadWadConfigFile();
  1590.         ProcessWadConfiguration();
  1591.     }
  1592.     else
  1593.     {
  1594.         Log("Using mapfile wad configuration\n");
  1595.     }
  1596.     if (!g_bWadConfigsLoaded)  // dont try and override wad.cfg
  1597. #endif
  1598.     {
  1599.         GetUsedWads(); 
  1600.     }
  1601.  
  1602. #ifdef HLCSG_AUTOWAD
  1603.     if (g_bWadAutoDetect)
  1604.     {
  1605.         Log("Wadfiles not in use by the map will be excluded\n");
  1606.     }
  1607. #endif
  1608.  
  1609.     DumpWadinclude();
  1610.     Log("\n");
  1611.  
  1612.     // if onlyents, just grab the entites and resave
  1613.     if (g_onlyents)
  1614.     {
  1615.         char            out[_MAX_PATH];
  1616.  
  1617.         safe_snprintf(out, _MAX_PATH, "%s.bsp", g_Mapname);
  1618.         LoadBSPFile(out);
  1619.         LoadWadincludeFile(g_Mapname);
  1620.  
  1621.         HandleWadinclude();
  1622.  
  1623.         // Write it all back out again.
  1624.         if (g_chart)
  1625.         {
  1626.             PrintBSPFileSizes();
  1627.         }
  1628.         WriteBSP(g_Mapname);
  1629.  
  1630.         end = I_FloatTime();
  1631.         LogTimeElapsed(end - start);
  1632.         return 0;
  1633.     }
  1634.     else
  1635.     {
  1636.         SaveWadincludeFile(g_Mapname);
  1637.     }
  1638.  
  1639. #ifdef HLCSG_CLIPECONOMY // AJM
  1640.     CheckForNoClip(); 
  1641. #endif
  1642.  
  1643.     // createbrush
  1644.     NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CreateBrush);
  1645.     CheckFatal();
  1646.  
  1647.     // boundworld
  1648.     BoundWorld();
  1649.  
  1650.     Verbose("%5i map planes\n", g_nummapplanes);
  1651.  
  1652.     // Set model centers
  1653.     NamedRunThreadsOnIndividual(g_numentities, g_estimate, SetModelCenters);
  1654.  
  1655.     // Calc brush unions
  1656.     if ((g_BrushUnionThreshold > 0.0) && (g_BrushUnionThreshold <= 100.0))
  1657.     {
  1658.         NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CalculateBrushUnions);
  1659.     }
  1660.  
  1661.     // open hull files
  1662.     for (i = 0; i < NUM_HULLS; i++)
  1663.     {
  1664.         char            name[_MAX_PATH];
  1665.  
  1666.         safe_snprintf(name, _MAX_PATH, "%s.p%i", g_Mapname, i);
  1667.  
  1668.         out[i] = fopen(name, "w");
  1669.  
  1670.         if (!out[i]) 
  1671.             Error("Couldn't open %s", name);
  1672.     }
  1673.  
  1674.     ProcessModels();
  1675.  
  1676.     Verbose("%5i csg faces\n", c_csgfaces);
  1677.     Verbose("%5i used faces\n", c_outfaces);
  1678.     Verbose("%5i tiny faces\n", c_tiny);
  1679.     Verbose("%5i tiny clips\n", c_tiny_clip);
  1680.  
  1681.     // close hull files 
  1682.     for (i = 0; i < NUM_HULLS; i++)
  1683.         fclose(out[i]);
  1684.  
  1685.     EmitPlanes();
  1686.  
  1687.     if (g_chart)
  1688.         PrintBSPFileSizes();
  1689.  
  1690.     WriteBSP(g_Mapname);
  1691.  
  1692.     // AJM: debug
  1693. #if 0
  1694.     Log("\n---------------------------------------\n"
  1695.         "Map Plane Usage:\n"
  1696.         "  #  normal             origin             dist   type\n"
  1697.         "    (   x,    y,    z) (   x,    y,    z) (     )\n"
  1698.         );
  1699.     for (i = 0; i < g_nummapplanes; i++)
  1700.     {
  1701.         plane_t* p = &g_mapplanes[i];
  1702.  
  1703.         Log(
  1704.         "%3i (%4.0f, %4.0f, %4.0f) (%4.0f, %4.0f, %4.0f) (%5.0f) %i\n",
  1705.         i,     
  1706.         p->normal[1], p->normal[2], p->normal[3],
  1707.         p->origin[1], p->origin[2], p->origin[3],
  1708.         p->dist,
  1709.         p->type
  1710.         );
  1711.     }
  1712.     Log("---------------------------------------\n\n");
  1713. #endif
  1714.  
  1715.     // elapsed time
  1716.     end = I_FloatTime();
  1717.     LogTimeElapsed(end - start);
  1718.  
  1719.     return 0;
  1720. }
  1721.